﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using MongoDB.Driver;
using MongoDB.Driver.Builders;

namespace DadaLib
{
    /// <summary>
    /// Basic generator with a single input text.
    /// </summary>
    [Serializable]
    public class Generator : IGenerator
    {
        private readonly string _fileName;
        private readonly MongoCollection<Biword> _biwords;
        public bool Weighted { get; set; }


        /// <summary>
        /// Initializes a new instance of the <see cref="Generator"/> class.
        /// </summary>
        public Generator(string fileName)
        {
            this._fileName = fileName;
            var ms = MongoServer.Create();
            var db = ms["dadaist"];
            _biwords = db.GetCollection<Biword>("biwords");
            Weighted = true;
        }

        /// <summary>
        /// Analizes the input text to create internal structures.
        /// </summary>
        public void Analize()
        {
            var parser = new FileParser(_fileName);
            var word1 = parser.GetNextWord();
            while (true)
            {
                var word2 = parser.GetNextWord();
                if ((word1 == null) || (word2 == null))
                    break;
                var id = word1 + " " + word2;
                var biword = _biwords.FindOneAs<Biword>(Query.EQ("_id", id));
                if (biword != null)
                    biword.Count++;
                else
                {
                    biword = new Biword { _id = id, Word1 = word1, Word2 = word2, Count = 1 };
                    _biwords.Insert(biword);
                }
                _biwords.Save(biword);
                word1 = word2;
            }
        }

        /// <summary>
        /// Gets the next word in sequence.
        /// </summary>
        /// <param name="seedWord">The seed word.</param>
        /// <returns></returns>
        public string GetNextWord(string seedWord)
        {
            var candidates = _biwords.FindAs<Biword>(Query.EQ("Word1", seedWord));
            var candidatesCount = candidates.Count();
            if ((seedWord == null) || candidatesCount == 0)
                return _biwords.FindOneAs<Biword>().Word1;
            
            var rnd = new Random();
            var i = Convert.ToInt32(rnd.NextDouble() * candidatesCount);
            var biword = candidates.Skip(i-1).FirstOrDefault();
            if (biword != null)
            return biword.Word2;
            throw new Exception("No word found.");
        }

        /// <summary>
        /// Searches for a word suitable for starting a sentence.
        /// </summary>
        /// <returns>A word</returns>
        public string SearchStartWord()
        {
            string word = GetNextWord(".");
            return word ?? GetNextWord(null);
        }


    }
}
